package com.fileex.frontend.web;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.netty.Constants;
import com.netty.Example;
import com.netty.HttpClient;
import com.netty.common.Result;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


@Controller
@RequestMapping("/file")
public class PageController {

    private ObjectMapper objectMapper = new ObjectMapper();

    @RequestMapping("")
    public String index(Model model) {
        model.addAttribute("serverIp", Constants.SERVER_IP);
        model.addAttribute("websocketPort", Constants.WEBSOCKET_PORT);
        return "files";
    }


    @RequestMapping("/listLocalFile")
    @ResponseBody
    public List<HashMap> listLocalFile(String path) {
        File[] fs = null;
        if (StringUtils.isEmpty(path)) {
            fs = File.listRoots();
        } else {
            fs = new File(path).listFiles();
        }
        List<HashMap> collect = Arrays.stream(fs).map(file -> {
            String filePath = StringUtils.isEmpty(file.getName()) ? file.getPath() : file.getName();
            HashMap map = new HashMap();
            map.put("name", filePath);
            map.put("path", file.getPath());
            if (file.isDirectory()) {
                map.put("leaf", false);
            } else {
                map.put("leaf", true);
            }
            return map;
        }).collect(Collectors.toList());
        return collect;
    }

    @RequestMapping("/listServerDir")
    @ResponseBody
    public Object listServerDir(String path) throws Exception {
        HttpClient httpClient = new HttpClient();
        HashMap params = new HashMap();
        params.put("path", StringUtils.isEmpty(path) ? "" : path);
        String result = httpClient.doPost(Constants.SERVER_URL + "file/listFileDir", params,false,null);
        Result serverResult = objectMapper.readValue(result, Result.class);
        if (serverResult.isSuccess()) {
            Object value = serverResult.getValue();
            return value;
        }
        throw new RuntimeException(serverResult.getMsg());
    }

    @RequestMapping("/listServerFile")
    @ResponseBody
    public Result listServerFile(String path, int page, int pageSize, String fileName) throws Exception {
        HttpClient httpClient = new HttpClient();
        HashMap params = new HashMap();
        params.put("directory", path);
        params.put("page", page);
        params.put("pageSize", pageSize);
        params.put("fileName", fileName);
        String result = httpClient.doPost(Constants.SERVER_URL + "file/page", params,false,null);
        Result serverResult = objectMapper.readValue(result, Result.class);
        return serverResult;
    }


    private static ConcurrentHashMap<String, HashMap<String, Object>> clientMap = new ConcurrentHashMap<String, HashMap<String, Object>>();



    @RequestMapping("/download")
    @ResponseBody
    public Result download(String downloadId,String fileId,
                           String downloadFilePath,
                           String fileName,
                           String websocketUser) throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                File file=new File(downloadFilePath+"/"+fileName);
                Long currentFileLength=0l;
                if (file.exists()){
                    currentFileLength=file.length();
                }
                HttpClient httpClient=new HttpClient();
                HashMap map = new HashMap();
                map.put("downloadId",downloadId);
                map.put("fileId",fileId);
                map.put("downloadFilePath",downloadFilePath);
                map.put("currentFileLength",currentFileLength);
                map.put("websocketUser",websocketUser);
                HashMap valueMap = new HashMap();
                valueMap.put("httpClient", httpClient);
                clientMap.put(downloadId, valueMap);
                httpClient.doPost(Constants.SERVER_URL + "file/download",map, true, downloadFilePath);
                httpClient.close();
                clientMap.remove(downloadId);
            }
        }).start();

        return Result.successResult();
    }




    @RequestMapping("/upload")
    @ResponseBody
    public Result upload(String uploadId,
                         String filePath,
                         String directory,
                         String websocketUser) throws Exception {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    HttpClient httpClient = new HttpClient();
                    HashMap header = new HashMap();
                    HashMap map = new HashMap();
                    map.put("directory", directory);
                    File file = new File(filePath);
                    map.put("file", file);
                    long fileLength = file.length();

                    String url = Constants.SERVER_URL + "file/save?uploadId=" + uploadId
                            + "&fileLength="
                            + fileLength
                            + "&websocketUser=" + websocketUser + "&directory=" + URLEncoder.encode(Base64.getEncoder().encodeToString(directory.getBytes("UTF-8")), "utf-8")
                            + "&clientFilePath=" + URLEncoder.encode(Base64.getEncoder().encodeToString(filePath.getBytes("UTF-8")), "utf-8");
                    //将自己的httpClient放到内存中
                    HashMap valueMap = new HashMap();
                    valueMap.put("httpClient", httpClient);
                    clientMap.put(uploadId, valueMap);
                    httpClient.doPostMultipart(url, map, header);
                    httpClient.close();
                    //上传结束，移除httpclient
                    clientMap.remove(uploadId);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        return Result.successResult();
    }


    @RequestMapping("/abortUploadOrDownload/{uuid}")
    @ResponseBody
    public Result abortUploadOrDownload(@PathVariable String uuid) {
        HashMap hashMap = clientMap.get(uuid);
        HttpClient httpClient = (HttpClient) hashMap.get("httpClient");
        httpClient.close();
        if (hashMap.containsKey("file")) {
            File fup = (File) hashMap.get("file");
            fup.delete();
        }
        clientMap.remove(uuid);
        return Result.successResult();
    }


    @RequestMapping("/abortAll")
    @ResponseBody
    public Result abortAll() {
        Collection<HashMap<String, Object>> values = clientMap.values();
        values.forEach(hashMap -> {
            HttpClient httpClient = (HttpClient) hashMap.get("httpClient");
            httpClient.close();
            if (hashMap.containsKey("file")) {
                File fup = (File) hashMap.get("file");
                fup.delete();
            }
        });
        clientMap.clear();
        return Result.successResult();
    }

    @RequestMapping("/loadUpload")
    @ResponseBody
    public Result loadUpload() throws Exception {
        HttpClient httpClient = new HttpClient();
        String json = (String) httpClient.doGet(Constants.SERVER_URL + "file/loadUpload", new HashMap());
        httpClient.close();
        ObjectMapper objectMapper = new ObjectMapper();
        Result result = objectMapper.readValue(json, Result.class);
        return result;
    }

    @RequestMapping("/loadDownload")
    @ResponseBody
    public Result loadDownload() throws Exception {
        HttpClient httpClient = new HttpClient();
        String json = (String) httpClient.doGet(Constants.SERVER_URL + "file/loadDownload", new HashMap());
        httpClient.close();
        ObjectMapper objectMapper = new ObjectMapper();
        Result result = objectMapper.readValue(json, Result.class);
        return result;
    }

    @RequestMapping("/cancelDownload")
    @ResponseBody
    public Result cancelDownload(String downloadId,String downloadFilePath,String fileName) throws Exception {
        HttpClient httpClient = new HttpClient();
        String json = (String) httpClient.doGet(Constants.SERVER_URL + "file/cancelDownload?downloadId="+downloadId, new HashMap());
        httpClient.close();
        ObjectMapper objectMapper = new ObjectMapper();
        Result result = objectMapper.readValue(json, Result.class);
        if (result.isSuccess()){
            File file=new File(downloadFilePath+"/"+fileName);
            file.delete();
        }
        return result;
    }


    @RequestMapping("/cancelUpload/{id}")
    @ResponseBody
    public Result cancelUpload(@PathVariable String id) throws Exception {
        HttpClient httpClient = new HttpClient();
        String json = (String) httpClient.doGet(Constants.SERVER_URL + "file/cancelUpload?uploadId="+id, new HashMap());
        httpClient.close();
        ObjectMapper objectMapper = new ObjectMapper();
        Result result = objectMapper.readValue(json, Result.class);
        return result;
    }

    @RequestMapping("/makeDir")
    @ResponseBody
    public Result makeDir(String dirName, String parentPath) throws Exception {
        HttpClient httpClient = new HttpClient();
        HashMap params = new HashMap();
        params.put("dirName", dirName);
        params.put("parentPath", parentPath);
        String json = (String) httpClient.doPost(Constants.SERVER_URL + "file/makeDir", params,false,null);
        httpClient.close();
        ObjectMapper objectMapper = new ObjectMapper();
        Result result = objectMapper.readValue(json, Result.class);
        return result;
    }


    @RequestMapping("/goOnUpload")
    @ResponseBody
    public Result goOnUpload(String uploadId, String filePath, String directory,
                             String websocketUser) throws Exception {
        HttpClient httpClient = new HttpClient();
        HashMap map = new HashMap();
        map.put("uploadId", uploadId);
        String json = (String) httpClient.doGet(Constants.SERVER_URL + "file/getTmpFileSize", map);
        httpClient.close();
        ObjectMapper objectMapper = new ObjectMapper();
        Result result = objectMapper.readValue(json, Result.class);
        final String oriFilePath = filePath;
        if (result.isSuccess()||result.getCode()==800) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        File file = new File(oriFilePath);
                        long fileLength = file.length();
                        HashMap dataMap = new HashMap();
                        dataMap.put("directory", directory);
                        //将自己的httpClient放到内存中
                        HttpClient httpClientMulti = new HttpClient();
                        HashMap valueMap = new HashMap();
                        valueMap.put("httpClient", httpClientMulti);
                        File fup=null;
                        if (result.getCode()==800){
                            dataMap.put("file", file);
                        }else{
                            HashMap value = (HashMap) result.getValue();
                            String length = value.get("length").toString();
                            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                            randomAccessFile.seek(Long.valueOf(length));
                            String name = file.getName();
                            String editFilePath = oriFilePath.replaceAll(name, "");
                            fup = new File(editFilePath + "fup" + UUID.randomUUID().toString());
                            if (!fup.exists()) {
                                fup.createNewFile();
                            }
                            FileOutputStream fileOutputStream = new FileOutputStream(fup);
                            byte[] bytes = new byte[1024];
                            int temp = 0;
                            while ((temp = randomAccessFile.read(bytes)) != -1) {
                                fileOutputStream.write(bytes, 0, temp);
                            }
                            randomAccessFile.close();
                            fileOutputStream.close();
                            dataMap.put("file", fup);
                            valueMap.put("file", fup);
                        }
                        HashMap header = new HashMap();
                        String url = Constants.SERVER_URL + "file/save?uploadId=" + uploadId
                                + "&fileLength="
                                + fileLength
                                + "&websocketUser=" + websocketUser + "&directory=" + URLEncoder.encode(Base64.getEncoder().encodeToString(directory.getBytes("UTF-8")), "utf-8")
                                + "&clientFilePath=" + URLEncoder.encode(Base64.getEncoder().encodeToString(oriFilePath.getBytes("UTF-8")), "utf-8");


                        clientMap.put(uploadId, valueMap);
                        httpClientMulti.doPostMultipart(url, dataMap, header);
                        httpClientMulti.close();
                        //删除临时文件
                        if (fup!=null){
                            fup.delete();
                        }
                        //上传结束，移除httpclient
                        clientMap.remove(uploadId);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } else {
            return result;
        }
        return Result.successResult();
    }


}


